<script setup>
import { ref, nextTick, watch, computed, defineEmits } from 'vue'
import * as echarts from 'echarts'
import { NThing } from 'naive-ui'

const emits = defineEmits(['exists', 'sign', 'upload'])
const model = defineModel(false)
const props = defineProps({
    existsUrl: {
        type: String
    },
    uploadUrl: {
        type: String
    },
    file: {
        type: Object
    },
    width: {
        type: String,
        default: '50vw'
    },
    signValue: {
        type: String
    },
    savePath: {
        type: String
    }
})
const menus = ref([])
watch(
    () => model.value,
    () => renderChart()
)
watch(
    () => menus.value.length,
    () => renderChart()
)

const renderChart = () => {
    if (model.value) {
        nextTick(() => {
            if (menus.value.includes('sign')) {
                signChartRender()
            }
            if (menus.value.includes('upload')) {
                uploadChartRender()
            }
        })
    }
}

const barWidth = ref(15)

//#region 上传图表
let uploadWidth = ref(0)
let uploadChart = {}
const uploadChartRef = ref()
const uploadChartRender = () => {
    uploadChart = echarts.init(uploadChartRef.value)
    function map() {
        return (
            props.file?.chunks?.map(it => ({
                index: it.index,
                percentage: it.progress.percentage,
                current: it.progress.current,
                total: it.progress.total,
                duration: it.duration
            })) || []
        )
    }
    props.file.onChunkUploadProgress = (e, a) => {
        uploadChart.setOption({
            dataset: [
                {
                    source: map()
                }
            ]
        })
        uploadChart.dispatchAction({
            type: 'dataZoom',
            startValue: e.index - 20,
            endValue: e.index
        })
    }

    const option = {
        title: {
            text: '分块上传详情'
        },
        dataset: [
            {
                dimensions: ['index', 'percentage', 'current', 'total', 'duration'],
                source: map()
            }
        ],
        tooltip: {
            trigger: 'axis',
            axisPointer: {
                type: 'shadow'
            },
            formatter: function (params) {
                const { index, total, percentage, duration } = params[0].data
                return [
                    '文件块上传进度',
                    '<br/>编号: ' + index,
                    '<br/>大小: ' + toFriendlySize(total),
                    '<br/>耗时: ' + time(duration),
                    '<br/>进度: ' + percentage + ' %'
                ].join('')
            }
        },
        legend: {
            orient: 'horizontal',
            selected: {
                current: false,
                duration: true
            }
        },
        grid: {
            left: 0,
            right: 0,
            bottom: 0,
            containLabel: true
        },
        xAxis: {
            type: 'category'
        },
        yAxis: {
            type: 'value',
            splitLine: { show: false }
        },
        dataZoom: [
            {
                type: 'slider',
                show: true,
                startValue: 0,
                endValue: 20,
                brushSelect: false
            }
        ],
        series: [
            {
                name: '块大小',
                type: 'bar',
                label: {
                    show: true,
                    position: 'top',
                    formatter: params => toFriendlySize(params.value.current)
                },
                encode: {
                    x: 'index',
                    y: 'current'
                },
                barMaxWidth: barWidth.value
            },
            {
                name: '耗时',
                type: 'bar',
                label: {
                    show: true,
                    position: 'top',
                    formatter: params => time(params.value.duration)
                },
                encode: {
                    x: 'index',
                    y: 'duration'
                },
                barMaxWidth: barWidth.value
            }
        ]
    }
    uploadChart.setOption(option)
    uploadWidth.value = signChart.getWidth()
}
watch(
    () => uploadWidth.value,
    () => {
        const endValue = Math.floor(uploadWidth.value / (barWidth.value + 25))
        uploadChart.setOption({
            dataZoom: [
                {
                    type: 'slider',
                    show: true,
                    startValue: 0,
                    endValue: endValue
                }
            ]
        })
    }
)

//#endregion

//#region 签名图表
let signChart = {}
let signWidth = ref(0)
let progress = ref([])
const signChartRef = ref()
const signChartRender = () => {
    signChart = echarts.init(signChartRef.value)

    props.file.onSignProgress = event => {
        progress.value.push(event)
        signChart.setOption({
            dataset: [
                {
                    source: progress.value
                }
            ]
        })
    }
    const option = {
        title: {
            text: '签名计算详情'
        },
        dataset: [
            {
                dimensions: ['diff', 'length', 'current', 'percentage'],
                source: []
            }
        ],
        tooltip: {
            trigger: 'axis',
            axisPointer: {
                type: 'shadow'
            },
            formatter: function (params) {
                const { diff, length, current, percentage } = params[0].data
                return [
                    '文件签名进度',
                    '<br/>耗时: ' + diff,
                    '<br/>大小: ' + toFriendlySize(length),
                    '<br/>累计: ' + toFriendlySize(current),
                    '<br/>进度: ' + percentage + ' %'
                ].join('')
            }
        },
        legend: {
            orient: 'horizontal',
            selected: {
                length: false,
                current: true,
                percentage: false
            }
        },
        grid: {
            left: 0,
            right: 0,
            bottom: 0,
            containLabel: true
        },
        xAxis: {
            type: 'category'
        },
        yAxis: {
            type: 'value',
            splitLine: { show: false }
        },
        dataZoom: [
            {
                type: 'slider',
                show: true,
                startValue: 0,
                endValue: 20,
                brushSelect: false
            }
        ],
        series: [
            {
                name: 'length',
                type: 'bar',
                label: {
                    show: true,
                    position: 'top',
                    formatter: params => {
                        return toFriendlySize(params.value.length)
                    }
                },
                barWidth: barWidth.value
            },
            {
                name: 'current',
                type: 'bar',
                label: {
                    show: true,
                    position: 'top',
                    formatter: params => toFriendlySize(params.value.current)
                },
                encode: {
                    x: 'timestamp',
                    y: 'current'
                },
                barWidth: barWidth.value
            },
            {
                name: 'percentage',
                type: 'bar',
                label: {
                    show: true,
                    position: 'top',
                    formatter: params => params.value.percentage + ' %'
                },
                encode: {
                    x: 'timestamp',
                    y: 'percentage'
                },
                barWidth: barWidth.value
            }
        ]
    }
    signChart.setOption(option)
    signWidth.value = signChart.getWidth()
}
watch(
    () => signWidth.value,
    () => {
        const endValue = Math.floor(signWidth.value / (barWidth.value + 25))
        signChart.setOption({
            dataZoom: [
                {
                    type: 'slider',
                    show: true,
                    startValue: 0,
                    endValue: endValue
                }
            ]
        })
    }
)

//#endregion

const upload = async () => {
    emits('upload')
}
const exists = async () => {
    emits('exists')
}
const sign = async () => {
    emits('sign')
}
const tags = ref([])
const rules = {
    chunkSize: {
        required: true,
        trigger: ['blur'],
        message: '请输入块大小'
    },
    batchSize: {
        required: true,
        trigger: ['blur'],
        message: '请输入批大小'
    }
}
const StateEnum = {
    EXISTING: 0,
    SIGNING: 1,
    WAITING: 2,
    UPLOADING: 3,
    SUCCESS: 4,
    ERROR: 5
}
const state = ref(StateEnum.WAITING)
const dot = computed(() => {
    switch (state.value) {
        case StateEnum.WAITING:
            return 'warning'
        case StateEnum.UPLOADING:
            return 'info'
        case StateEnum.SUCCESS:
            return 'success'
        case StateEnum.ERROR:
            return 'error'
    }
})
</script>

<template>
    <n-modal
        v-model:show="model"
        :style="{ width: width }"
        preset="card"
        title="上传详情"
        size="huge"
        :bordered="false">
        <n-scrollbar style="max-height: 70vh">
            <n-thing :content-indented="true">
                <template #avatar>
                    <n-badge dot :type="dot">
                        <n-avatar>
                            <n-icon>
                                <CashIcon />
                            </n-icon>
                        </n-avatar>
                    </n-badge>
                </template>
                <template #header>{{ file?.name }}</template>
                <template #header-extra>
                    {{ file?.completedCount }}/{{ file?.chunks?.length }}
                </template>
                <template #description>
                    <n-form
                        ref="formRef"
                        :model="file"
                        :rules="rules"
                        label-placement="left"
                        label-width="70px"
                        :show-feedback="false"
                        label-align="left"
                        size="small">
                        <n-flex vertical>
                            <n-form-item label="文件签名" path="signatured">
                                <n-switch v-model:value="file.signatured">
                                    <template #checked>启用</template>
                                    <template #unchecked>禁用</template>
                                </n-switch>
                            </n-form-item>
                            <n-form-item label="块大小" path="chunkSize">
                                <n-flex :wrap="false">
                                    <n-input v-model:value="file.chunkSizeUnit" />
                                    <n-button>设为默认值</n-button>
                                </n-flex>
                            </n-form-item>
                            <n-form-item label="批大小" path="batchSize">
                                <n-flex :wrap="false">
                                    <n-input v-model:value="file.batchSize" />
                                    <n-button>设为默认值</n-button>
                                </n-flex>
                            </n-form-item>
                            <n-form-item label="文件标签" path="tags">
                                <n-dynamic-tags v-model:value="tags" />
                            </n-form-item>
                            <n-form-item label="文件标签" path="tags">
                                <n-checkbox-group v-model:value="menus">
                                    <n-flex>
                                        <n-checkbox value="sign">签名图表</n-checkbox>
                                        <n-checkbox value="upload">上传图表</n-checkbox>
                                    </n-flex>
                                </n-checkbox-group>
                            </n-form-item>
                            <div>验证地址：{{ existsUrl }}</div>
                            <div>上传地址：{{ uploadUrl }}</div>
                            <div v-if="signValue">
                                <span>文件签名：</span>
                                <n-tag size="small" type="success">
                                    {{ signValue }}
                                </n-tag>
                            </div>
                            <div v-if="savePath">
                                <span>保存路径：</span>
                                <n-tag size="small" type="success">
                                    {{ savePath }}
                                </n-tag>
                            </div>
                        </n-flex>
                    </n-form>
                </template>
                <div class="remark">
                    此文件于
                    {{ file?.lastModified }}
                    创建，大小为 {{ file?.size }}，现将其以
                    {{ file?.chunkSizeUnit }}
                    大小的块拆分，共拆分成
                    {{ file?.chunks?.length }}
                    块，然后将这
                    {{ file?.chunks?.length }}
                    块以
                    {{ file?.batchSize }}
                    个块为一个批次上传至服务器， 共计
                    {{ file?.batchs?.length }}
                    个批次。
                </div>
                <template #footer>
                    <n-flex>
                        <n-tag type="info" size="small" round>
                            {{ file?.lastModified }}
                        </n-tag>
                        <n-tag type="info" size="small" round>
                            {{ file?.size }}
                        </n-tag>
                    </n-flex>
                </template>
                <template #action></template>
            </n-thing>
            <div v-if="menus.includes('sign')" class="chart" ref="signChartRef"></div>
            <div v-if="menus.includes('upload')" class="chart" ref="uploadChartRef"></div>
        </n-scrollbar>
        <template #footer>
            <n-flex justify="end">
                <n-button
                    v-if="file?.signatured && !file?.signValue"
                    @click="sign"
                    :loading="file?.state == StateEnum.SIGNING">
                    计算签名
                </n-button>
                <n-button @click="exists" :loading="file?.state == StateEnum.EXISTING">
                    验证是否存在
                </n-button>
                <n-button @click="upload" :loading="file?.state == StateEnum.UPLOADING" type="info">
                    开始上传
                </n-button>
            </n-flex>
        </template>
    </n-modal>
</template>

<style scoped>
.chart {
    padding-top: 16px;
    height: 300px;
    width: 100%;
}
.remark {
    font-size: 13px;
    color: #7c7c7c;
}
</style>
